package com.acegear.horizon.controllers;

import com.acegear.horizon.controllers.vo.ResultVO;
import com.acegear.horizon.domain.models.Club;
import com.acegear.horizon.domain.models.ClubEvent;
import com.acegear.horizon.domain.models.User;
import com.acegear.horizon.domain.models.constraint.ClubEventState;
import com.acegear.horizon.domain.models.constraint.FeedType;
import com.acegear.horizon.domain.models.constraint.RecommendType;
import com.acegear.horizon.domain.models.jpa.ClubClaim;
import com.acegear.horizon.domain.models.jpa.ClubFeed;
import com.acegear.horizon.domain.models.vo.FeedVO;
import com.acegear.horizon.domain.models.vo.UserPostVO;
import com.acegear.horizon.domain.repository.ClubEventRepository;
import com.acegear.horizon.domain.repository.ClubRepository;
import com.acegear.horizon.domain.repository.UserRepository;
import com.acegear.horizon.domain.services.ClubService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Created by wangsike on 2016/12/21.
 */
@RestController
@RequestMapping("/clubs")
public class ClubController {

    @Autowired
    private ClubRepository clubRepository;

    @Autowired
    private ClubEventRepository clubEventRepository;

    @Autowired
    private ClubService clubService;

    @Autowired
    private UserRepository userRepository;

    @RequestMapping(value = "", method = RequestMethod.GET)
    public ResultVO getClubs(@RequestHeader(value = "X-Consumer-Username", defaultValue = "0") Long userId,
                             @RequestParam(value = "register", defaultValue = "false") boolean register,
                             int page, int count) {
        Pageable pageable = new PageRequest(page, count);
        return new ResultVO<>(clubRepository
                .query(register, pageable)
                .map(club -> club.getClubVO(userId))
                .collect(Collectors.toList()));
    }

    @RequestMapping(value = "/{clubId}", method = RequestMethod.GET)
    public ResultVO getClub(@PathVariable Long clubId,
                            @RequestHeader(value = "X-Consumer-Username") Long userId) {
        Optional<Club> clubOptional = clubRepository.findByClubId(clubId);
        if (clubOptional.isPresent()) {
            Club club = clubOptional.get();
            return new ResultVO<>(club.getClubVO(userId));
        } else {
            return ResultVO.CLUB_NOT_FOUND;
        }
    }

    @RequestMapping(value = "/{clubId}/shareInfo", method = RequestMethod.GET)
    public ResultVO getClubShareInfo(@PathVariable Long clubId) {
        Optional<Club> clubOptional = clubRepository.findByClubId(clubId);
        if (clubOptional.isPresent()) {
            Club club = clubOptional.get();
            return new ResultVO<>(club.getShareInfoVO());
        } else {
            return ResultVO.CLUB_NOT_FOUND;
        }
    }

    @RequestMapping(value = "/{clubId}/info", method = RequestMethod.GET)
    public ResultVO getClubInfo(@PathVariable Long clubId) {
        Optional<Club> clubOptional = clubRepository.findByClubId(clubId);
        if (clubOptional.isPresent()) {
            Club club = clubOptional.get();
            return new ResultVO<>(club.getInfo());
        } else {
            return ResultVO.CLUB_NOT_FOUND;
        }
    }

    @RequestMapping(value = "/{clubId}/feeds", method = RequestMethod.GET)
    public ResultVO getClubFeeds(@PathVariable Long clubId, Integer page, Integer count,
                                 @RequestHeader(value = "X-Consumer-Username", required = false, defaultValue = "0") Long viewerId) {

        Pageable pageable = new PageRequest(page, count);
        Optional<Club> clubOptional = clubRepository.findByClubId(clubId);
        if (clubOptional.isPresent()) {
            Club club = clubOptional.get();
            return new ResultVO<>(club.getClubPosts(viewerId, pageable));
        } else {
            return ResultVO.CLUB_NOT_FOUND;
        }
    }

    /**
     * 获取某个clud的post列表
     */
    @RequestMapping(value = "/{clubId}/posts", method = RequestMethod.GET)
    public ResultVO getClubPostFeed(@PathVariable Long clubId, Integer page, Integer count,
                                    @RequestHeader(value = "X-Consumer-Username", required = false, defaultValue = "0") Long viewerId) {
        List<UserPostVO> result = new ArrayList<>();
        //如果是第一页，就把置顶的也拼接过去
        if (page == 0) {
            //最大置顶10个
            Pageable pageable = new PageRequest(0, 10, Sort.Direction.DESC, "position");
            result.addAll(clubService.getPostsByClubId(clubId, true, pageable, viewerId));
        }
        Pageable pageable = new PageRequest(page, count, Sort.Direction.DESC, "position");
        result.addAll(clubService.getPostsByClubId(clubId, false, pageable, viewerId));
        return new ResultVO<>(result);
    }

    /**
     * 获取某个clud的feed流列表，除了post的
     */
    @RequestMapping(value = "/{clubId}/other", method = RequestMethod.GET)
    public ResultVO getClubFeedsWithoutPost(@PathVariable Long clubId, Integer page, Integer count,
                                            @RequestHeader(value = "X-Consumer-Username", required = false, defaultValue = "0") Long viewerId) {
        List<FeedVO> result = new ArrayList<>();
        if (page == 0) {
            //最大置顶10个
            Pageable pageable = new PageRequest(0, 10, Sort.Direction.DESC, "position");
            result.addAll(clubService.getFeedByCludIdWithNoPost(clubId, true, pageable, viewerId));
        }
        Pageable pageable = new PageRequest(page, count, Sort.Direction.DESC, "position");
        result.addAll(clubService.getFeedByCludIdWithNoPost(clubId, false, pageable, viewerId));
        return new ResultVO<>(result);
    }

    /**
     * 置顶某个feed
     */
    @RequestMapping(value = "/topFeed", method = RequestMethod.POST)
    public ResultVO topPost(Long clubId, Long relateId, FeedType feedType) {
        Map<String, Boolean> result = new HashMap<>();
        ClubFeed feed = clubRepository.topFeed(clubId, relateId, feedType);
        if (feed == null) {
            return ResultVO.TOP_FAIL;
        }
        result.put("success", true);
        return new ResultVO<>(result);
    }

    /**
     * 取消置顶
     */
    @RequestMapping(value = "/unTopFeed", method = RequestMethod.POST)
    public ResultVO unTop(Long clubId, Long relateId, FeedType feedType) {
        Map<String, Boolean> result = new HashMap<>();
        ClubFeed feed = clubRepository.unTopFeed(clubId, relateId, feedType);
        if (feed == null) {
            return ResultVO.UNTOP_FAIL;
        }
        result.put("success", true);
        return new ResultVO<>(result);
    }

    @RequestMapping(value = "/{clubId}/members", method = RequestMethod.GET)
    public ResultVO getClubMembers(@PathVariable Long clubId, Integer page, Integer count,
                                    Long viewerId) {
        Pageable pageable = new PageRequest(page, count, Sort.Direction.DESC, "rank");
        Optional<Club> clubOptional = clubRepository.findByClubId(clubId);
        if (clubOptional.isPresent()) {
            Club club = clubOptional.get();
            return new ResultVO<>(club.getMembers(clubId,pageable));
        } else {
            return ResultVO.CLUB_NOT_FOUND;
        }
    }

    @RequestMapping(value = "/{clubId}/members", method = RequestMethod.POST)
    @Transactional
    public ResultVO joinClub(@PathVariable Long clubId,
                             @RequestHeader(value = "X-Consumer-Username") Long userId) {
        Map<String, Boolean> result = new HashMap<>();
        if (userRepository
                .findByUserId(userId)
                .map(user -> user.joinClub(clubId))
                .orElse(false)) {
            result.put("success", true);
            return new ResultVO<>(result);
        } else {
            return ResultVO.JOIN_ERROR;
        }
    }

    @RequestMapping(value = "/{clubId}/members", method = RequestMethod.DELETE)
    @Transactional
    public ResultVO leaveClub(@PathVariable Long clubId,
                              @RequestHeader(value = "X-Consumer-Username") Long userId) {
        Map<String, Boolean> result = new HashMap<>();
        Optional<User> userOptional = userRepository.findByUserId(userId);
        if (userOptional.isPresent()) {
            userOptional.get().leaveClub(clubId);
            result.put("success", true);
            return new ResultVO<>(result);
        } else {
            return ResultVO.LEAVE_ERROR;
        }
    }

    @RequestMapping(value = "/{clubId}/events", method = RequestMethod.GET)
    public ResultVO getEvents(@PathVariable Long clubId, ClubEventState eventState, Integer page, Integer count) {
        PageRequest pageRequest = new PageRequest(page, count);
        return new ResultVO<>(clubEventRepository.queryEvent(clubId, null, eventState, pageRequest)
                .map(ClubEvent::getEventVO)
                .collect(Collectors.toList()));
    }

    @RequestMapping(value = "/{clubId}/claim", method = RequestMethod.POST)
    public ResultVO claimClub(@PathVariable Long clubId, ClubClaim clubClaim,
                              @RequestHeader(value = "X-Consumer-Username") Long userId) {
        Map<String, Boolean> result = new HashMap<>();
        Optional<Club> clubOptional = clubRepository.findByClubId(clubId);
        if (clubOptional.isPresent()) {
            Optional<User> userOptional = userRepository.findByUserId(userId);
            if (userOptional.isPresent()) {
                clubClaim.setUserId(userId);
                clubOptional.get().saveClubClaim(clubClaim);
                result.put("success", true);
                return new ResultVO<>(result);
            } else {
                return ResultVO.USER_NOT_FOUND;
            }
        } else {
            return ResultVO.CLUB_NOT_FOUND;
        }
    }

    @RequestMapping(value = "/{clubId}/claim/{claimId}", method = RequestMethod.GET)
    @Transactional
    public ResultVO claimClub(@PathVariable Long clubId, @PathVariable Long claimId) {
        Optional<Club> clubOptional = clubRepository.findByClubId(clubId);
        if (clubOptional.isPresent()) {
            return new ResultVO<>(clubOptional.get().queryClubClaim(claimId));
        } else {
            return ResultVO.CLUB_NOT_FOUND;
        }
    }

    @RequestMapping(value = "/recommend", method = RequestMethod.GET)
    public ResultVO getClubRecommend(Integer page, Integer count,
                                     @RequestHeader(value = "X-Consumer-Username", defaultValue = "0") Long viewerId) {
        Pageable pageable = new PageRequest(page, count, Sort.Direction.ASC, "pos");
        return new ResultVO<>(clubService.getClubVO(pageable, viewerId, RecommendType.CLUB));
    }

    @RequestMapping(value = "/recommend/personal", method = RequestMethod.GET)
    public ResultVO getClubPersonalRecommend(Integer page, Integer count,
                                             @RequestHeader(value = "X-Consumer-Username", defaultValue = "0") Long viewerId) {
        Pageable pageable = new PageRequest(page, count, Sort.Direction.ASC, "pos");
        return new ResultVO<>(clubService.getClubVO(pageable, viewerId, RecommendType.PERSONALCLUB));
    }

    @RequestMapping(value = "/recommend/carousel", method = RequestMethod.GET)
    public ResultVO getClubCarouselRecommend(Integer page, Integer count,
                                             @RequestHeader(value = "X-Consumer-Username", defaultValue = "0") Long viewerId) {
        Pageable pageable = new PageRequest(page, count, Sort.Direction.ASC, "pos");
        return new ResultVO<>(clubService.getClubVO(pageable, viewerId, RecommendType.CLUBHOMECAROUSEL));
    }

    @RequestMapping(value = "/recommend/hot", method = RequestMethod.GET)
    public ResultVO getClubHotRecommend(Integer page, Integer count,
                                        @RequestHeader(value = "X-Consumer-Username", defaultValue = "0") Long viewerId) {
        Pageable pageable = new PageRequest(page, count, Sort.Direction.ASC, "pos");
        return new ResultVO<>(clubService.getClubVO(pageable, viewerId, RecommendType.CLUBHOMEHOT));
    }

    @RequestMapping(value = "/recommend/all", method = RequestMethod.GET)
    public ResultVO getClubAllRecommend(Integer page, Integer count,
                                        @RequestHeader(value = "X-Consumer-Username", defaultValue = "0") Long viewerId) {
        Pageable pageable = new PageRequest(page, count, Sort.Direction.ASC, "pos");
        return new ResultVO<>(clubService.getClubVO(pageable, viewerId, RecommendType.CLUBHOMEALL));
    }
}